package com.lan.extend.dict.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.lan.extend.dict.cache.IDictCache;
import com.lan.extend.dict.config.CacheProperties;
import com.lan.extend.dict.scanner.LanDictAnnotationScanner;
import com.lan.extend.dict.service.IDictService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

@Service
public class DictServiceImpl implements IDictService {

    private static final Logger log = LogManager.getLogger(DictServiceImpl.class);

    @Autowired
    private LanDictAnnotationScanner scanner;

    @Autowired(required = false)
    private IDictCache dictCache;

    @Autowired
    private CacheProperties cacheProperties;

    /**
     * 根据字典键值获取对应数据
     *
     * @param key 键名
     * @return
     */
    @Override
    public Map<String, List<Map<String, Object>>> getDictList(String key) {
        scanner.init();
        List<Map<String, Object>> list = new ArrayList<>();
        try {
            Object bean = scanner.getBean(key);
            if (bean == null) return error(key);

            Method method = scanner.getMethod(key, bean);

            Map<String, Map<String, String>> keyMap = scanner.getFieldList(key);
            if (keyMap == null) return error(key);

            for (Object obj : (List) method.invoke(bean)) {
                JSONObject from = JSONObject.from(obj);
                HashMap<String, Object> map = new HashMap<>();
                for (String s : keyMap.keySet()) {
                    Object o = from.get(s);
                    map.put(keyMap.get(s).get("key"), Objects.requireNonNullElseGet(o, Optional::empty));
                }
                list.add(map);
            }
        } catch (NoSuchMethodException e) {
            log.error("方法不存在！", e);
        } catch (IllegalAccessException e) {
            log.error("实例化类失败！", e);
        } catch (InvocationTargetException e) {
            log.error("调用实例化类方法失败！", e);
        }
        Map<String, List<Map<String, Object>>> data = new HashMap<>();
        data.put(key, list);
        return data;
    }

    /**
     * 根据字典键值获取对应数据
     *
     * @param keys 键名数组
     * @return
     */
    @Override
    public Map<String, List<Map<String, Object>>> getDictList(String[] keys) {
        scanner.init();
        Map<String, List<Map<String, Object>>> data = new HashMap<>();
        for (String key : keys) {
            Map<String, List<Map<String, Object>>> dictList = null;
            //判断配置文件是否开启并实现了缓存接口
            if(cacheProperties.getEnabled() && dictCache != null) {
                dictList = getDictCache(key);
            } else {
                dictList = getDictList(key);
            }
            data.putAll(dictList);
        }
        return data;
    }

    /**
     * 设置缓存
     * @param key 需要缓存的键
     * @param dictList 需要缓存的值
     */
    private void setDictCache(String key, List<Map<String, Object>> dictList){
        long refreshTime = scanner.getRefreshTime(key);
        dictCache.put(cacheProperties.getDictKeyName(), key, dictList, refreshTime == 0 ? cacheProperties.getRefreshTime() : refreshTime);
    }

    /**
     * 读取缓存
     * @param key 需要缓存的键
     */
    private Map<String, List<Map<String, Object>>> getDictCache(String key){
        List<Map<String, Object>> list = null;
        //判断注解是否开启了缓存
        if(scanner.enabled(key)) {
            list = dictCache.getList(cacheProperties.getDictKeyName(), key);
            //缓存数据不存在
            if(list == null) {
                list = getDictList(key).get(key);
                setDictCache(key, list);
            }
        }
        if(list == null) list = new ArrayList<>();
        Map<String, List<Map<String, Object>>> data = new HashMap<>();
        data.put(key, list);
        return data;
    }

    /**
     * 发生异常时默认值[]
     * @param key 键
     * @return
     */
    private Map<String, List<Map<String, Object>>> error(String key) {
        Map<String, List<Map<String, Object>>> data = new HashMap<>();
        data.put(key, new ArrayList<>());
        return data;
    }

}
